/**
 * Project: apollo-base-dal
 * 
 * File Created at 2016年5月6日
 * 
 * Copyright 2015-2016 dx.com Croporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * DongXue software Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with dx.com.
 */
package com.dx.pf.dal.jdbc.sql;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.dx.pf.dal.Logger;
import com.dx.pf.dal.constants.DalConstant;
import com.dx.pf.dal.constants.Operator;

/**
 * @ClassName: Condition
 * @Description: where条件组装
 * @author wuzhenfang(wzfbj2008@163.com)
 * @date 2016年5月6日 上午10:15:06
 * @version V1.0
 */
public class Condition {

	private final static Logger logger = Logger.getLogger(Condition.class);

	private String[] colNames = null;// 当前列名称
	private Operator[] operates = null;// 当前操作符名称
	private Object[] values = null;// 当前值

	private boolean isAnd = true;// 本次做的是and操作

	protected StringBuilder condiSQL = new StringBuilder(256);
	
	protected Map<String, Object> conditionParam = new HashMap<String, Object>();

	/**
	 * 条件组装器
	 * @param colNames 列名称
	 * @param operates 操作符
	 * @param values 值
	 * @throws SQLException
	 */
	public Condition(String[] colNames, Operator[] operates, Object[] values) throws SQLException {
		if ((colNames.length == operates.length) && colNames.length == values.length) {
			this.colNames = colNames;
			this.operates = operates;
			this.values = values;

			int index = 0;
			for (int i = 0; i < this.colNames.length; i++) {
				if (index != 0) {
					condiSQL.append(DalConstant.sql_and);
				}
				// 验证列名是否合法
				String colName = colNames[i];
				if (conditionParam.get(colName) != null) {
					colName = colName + "_" + i;
				}

				if (this.operates[i].equals(Operator.IN)) {// 处理in
					condiSQL.append(" ").append(this.colNames[i]).append(this.operates[i].getSqlVal()).append(" (:").append(colName).append(" ) ");
					this.values[i] = processInOparetorToList(this.values[i]);
				} else if ((this.operates[i].equals(Operator.IS_NOT) || this.operates[i].equals(Operator.IS))
						&& (null == this.operates[i].getSqlVal() || "null".equalsIgnoreCase(this.operates[i].getSqlVal()))) {
					condiSQL.append(" ").append(this.colNames[i]).append(this.operates[i].getSqlVal()).append(" null ");
				} else {
					condiSQL.append(" ").append(this.colNames[i]).append(this.operates[i].getSqlVal()).append(" :").append(colName).append(" ");
				}
				conditionParam.put(colName, this.values[i]);
				index++;
			}
			isAnd = true;
		} else {
			logger.error("设置where条件属性错误。");
			throw new SQLException("设置where条件属性错误。");
		}
	}

	/***
	 * 条件and
	 * @param condition
	 * @return
	 */
	public Condition and(Condition condition) {
		condition = replaceRepeatParam(condition);
		if (isAnd && condition.isAnd) {// and操作
			process(condition.condiSQL, DalConstant.sql_and, false);
		} else {// 上一次做的是or操作
			process(condition.condiSQL, DalConstant.sql_and, true);
		}
		this.putAllConditionParam(condition.getConditionParam());
		isAnd = true;
		return this;
	}

	/**
	 * 条件或者
	 * @param condition
	 * @return
	 */
	public Condition or(Condition condition) {
		condition = replaceRepeatParam(condition);
		if (!isAnd && !condition.isAnd) {// or操作
			process(condition.condiSQL, DalConstant.sql_or, false);
		} else {// 上一次是做的and操作
			process(condition.condiSQL, DalConstant.sql_or, true);
		}
		this.putAllConditionParam(condition.getConditionParam());
		isAnd = false;
		return this;
	}

	/**
	 * 处理or或者and的子句
	 * @param newCondiSQL
	 * @param andOr
	 * @param needBracket
	 */
	private void process(StringBuilder newCondiSQL, String andOr, boolean needBracket) {
		StringBuilder sql = new StringBuilder(64);
		if (needBracket) {
			sql.append(DalConstant.bracket_l).append(condiSQL).append(DalConstant.bracket_r)
			.append(andOr).
			append(DalConstant.bracket_l).append(newCondiSQL).append(DalConstant.bracket_r);
		} else {
			sql.append(condiSQL).append(andOr).append(newCondiSQL);
		}
		this.condiSQL = sql;
	}

	/**
	 * 替换重复参数
	 * @param condition
	 * @return
	 */
	public Condition replaceRepeatParam(Condition condition) {
		// 处理两个条件中字段重复问题
		Map<String, Object> newConditionMapParam = new HashMap<String, Object>();
		String replacesql = condition.condiSQL.toString();
		newConditionMapParam.putAll(condition.getConditionParam());

		for (Iterator<Entry<String, Object>> entryKeyIterator = condition.getConditionParam().entrySet().iterator(); entryKeyIterator.hasNext();) {
			Map.Entry<String, Object> entry = entryKeyIterator.next();
			String key = entry.getKey();
			Object obj = entry.getValue();
			if (conditionParam.containsKey(key)) {
				int index = 1;
				StringBuilder keyStr = null;
				StringBuilder lastkeyStr = null;
				while (true) {
					keyStr = new StringBuilder(key);
					lastkeyStr = new StringBuilder(keyStr);
					keyStr.append("_").append(index);
					if ((!conditionParam.containsKey(keyStr.toString()) && !newConditionMapParam.containsKey(keyStr.toString())) || index > 10000) {// 为了保险index大于10000也跳出循环
						break;
					}
					index++;
				}
				newConditionMapParam.put(keyStr.toString(), obj);
				replacesql = replacesql.replaceFirst(":" + lastkeyStr.toString() + " ", ":" + keyStr.toString() + " ");
			} else {
				newConditionMapParam.put(key, obj);
			}
		}
		condition.condiSQL = new StringBuilder(replacesql);
		condition.conditionParam = newConditionMapParam;
		return condition;
	}
	
	/**
	 * 检查和处理in错误的值
	 * @param values
	 * @return
	 * @throws SQLException
	 */
	private Object processInOparetorToList(Object values) throws SQLException {
		if (values instanceof List) {// 是list
			return values;
		} else if (values.getClass().isArray()) {// 是数组
			return Arrays.asList(values);
		} else {
			throw new SQLException("设置in条件属性错误,需要为list类型。");
		}
	}

	
	
	/**
	 * @return the condiSQL
	 */
	public StringBuilder getCondiSQL() {
		return condiSQL;
	}

	/**
	 * @param condiSQL the condiSQL to set
	 */
	public void setCondiSQL(StringBuilder condiSQL) {
		this.condiSQL = condiSQL;
	}

	/**
	 * @return the conditionParam
	 */
	public Map<String, Object> getConditionParam() {
		return conditionParam;
	}

	/**
	 * @param conditionParam the conditionParam to set
	 */
	public void setConditionParam(Map<String, Object> conditionParam) {
		this.conditionParam = conditionParam;
	}

	public void putAllConditionParam(Map<String, Object> conditionParam) {
		this.conditionParam.putAll(conditionParam);
	}
	/**
	 * 获取条件sql片段
	 */
	public String toSQLString() {
		return condiSQL.toString();
	}
}
